package com.simple.business.service.user.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.zuihou.base.R;
import com.github.zuihou.base.service.SuperServiceImpl;
import com.simple.business.domain.dto.sms.LoginDTO;
import com.simple.business.domain.dto.sms.UserPwdChangeDTO;
import com.simple.business.domain.dto.sms.UserRegisterDTO;
import com.simple.business.domain.dto.sms.VerificationCodeDTO;
import com.simple.business.domain.entity.user.User;
import com.simple.business.domain.vo.login.UserLoginSuccessVO;
import com.simple.business.mapper.user.UserMapper;
import com.simple.business.service.user.UserService;
import com.simple.business.service.sms.VerificationCodeService;
import com.simple.common.utils.SecurityUtils;
import com.simple.common.utils.ip.IpUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class UserServiceImpl extends SuperServiceImpl<UserMapper, User> implements UserService {

    private static final String REDIS_RESET_PWD_CODE = "reset_pwd_code_";

    private static final String REDIS_USER_ID_CODE = "userService_user_id_code_";

    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private VerificationCodeService verificationCodeService;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;


    /**
     * 根据用户名获取用户
     * @param userName
     * @return
     */
    @Override
    public User getUserByUserName(String userName) {
        return getOne(Wrappers.<User>lambdaQuery()
                .eq(User::getUserName, userName)
                .eq(User::getDeleted, Boolean.FALSE));
    }

    /**
     * 普通账号密码注册
     * @param userRegisterDTO
     * @return
     */
    @Override
    public R<UserLoginSuccessVO> register(UserRegisterDTO userRegisterDTO) {
        int count = count(Wrappers.<User>lambdaQuery()
                .eq(User::getUserName, userRegisterDTO.getUserName())
                .eq(User::getDeleted, Boolean.FALSE));
        if (count > 0) {
            return R.fail("账号已存在");
        }
        if (StringUtils.isBlank(userRegisterDTO.getNickName())) {
            //生成随机昵称
            userRegisterDTO.setNickName(RandomStringUtils.randomAlphabetic(10));
        }
        User user = User.builder()
                .userName(userRegisterDTO.getUserName())
                .nickName(userRegisterDTO.getNickName())
                .mobile(userRegisterDTO.getMobile())
                .password(passwordEncoder.encode(userRegisterDTO.getPassword()))
                .status(Boolean.FALSE)
                .loginIp(IpUtils.getIpAddr())
                .loginTime(LocalDateTime.now())
                .build();
        save(user);

        UserLoginSuccessVO userLoginSuccessVO = new UserLoginSuccessVO();
        BeanUtils.copyProperties(user, userLoginSuccessVO);

        return R.success(userLoginSuccessVO);
    }

    /**
     * 手机发送验证码
     * @param dto
     * @return
     */
    @Override
    public R<String> sendSms(VerificationCodeDTO dto) {
        return verificationCodeService.sendSmsCode(dto.getAccount());
    }

    /**
     * 绑定手机
     * @param dto
     * @return
     */
    @Override
    public R<Boolean> bindPhoneOrEmail(LoginDTO dto) {
        Long userId = SecurityUtils.getUserId();
        R<Boolean> check = verificationCodeService.codeCheck(dto.getAccount(), dto.getCode(), true,userId,true);
        if (check.getIsError()) {
            return R.fail(check.getMsg());
        }

        User user = getOne(Wrappers.<User>lambdaQuery()
                .eq(User::getUserName, dto.getAccount())
                .last("order by create_time desc limit 1"));

        if (Objects.isNull(user)) {
            return R.fail("已被绑定，请重新操作。");
        }
        user.setMobile(dto.getAccount());
        updateById(user);
        return R.success(true);
    }

    @Override
    public UserLoginSuccessVO login(String userName, String pwd) {
        UserLoginSuccessVO vo = new UserLoginSuccessVO();
        User user = getOne(Wrappers.<User>lambdaQuery()
                .eq(User::getUserName, userName)
        );
        if (Objects.isNull(user) || user.getStatus()) {
            return vo;
        }

        if (!passwordEncoder.matches(pwd, user.getPassword())) {
            // todo 密码错误，记录错误次数
            user.setPasswordErrorLastTime(LocalDateTime.now());
            if (user.getPasswordErrorNum() == null) {
                user.setPasswordErrorNum(0);
            }
            user.setPasswordErrorNum(user.getPasswordErrorNum() + 1);
            updateById(user);
            return vo;
        }

        BeanUtils.copyProperties(user, vo);
        vo.setId(user.getId());
        return vo;
    }

    @Override
    public R<Boolean> changePwd(UserPwdChangeDTO dto) {
        User user = getById(SecurityUtils.getUserId());
        if (!passwordEncoder.matches(dto.getOldPwd(), user.getPassword())) {
            return R.fail("密码验证失败");
        }
        user.setPassword(passwordEncoder.encode(dto.getNewPwd()));
        updateById(user);
        return R.success(true);
    }


    @Override
    public R<Boolean> resetPwd() {
        User user = getById(SecurityUtils.getUserId());
        user.setPassword(passwordEncoder.encode("123456"));
        updateById(user);
        return R.success();
    }

    /**
     * 判断当前账号是否和输入账号一致
     * @param account
     * @return
     */
    @Override
    public boolean accountExist(String account) {
        User user = getById(SecurityUtils.getUserId());
        return user.getUserName().equals(account);
    }

    /**
     * 生成登录成功的用户身份code，用户未登录下手机号码绑定和再次登录
     */
    @Override
    public String genIdCode(UserLoginSuccessVO userLoginSuccessVO) {
        String id = UUID.randomUUID().toString().replace("-","");
        String key = REDIS_USER_ID_CODE +id;
        redisTemplate.opsForValue().set(key,userLoginSuccessVO,Duration.ofMinutes(30));
        return id;
    }

    @Override
    public R<UserLoginSuccessVO> simpleRegister(String account) {
        //注册一个账号
        User user = new User();
        user.setUserName(account + System.currentTimeMillis());
        user.setNickName(account + System.currentTimeMillis());
        user.setPassword(passwordEncoder.encode("123456"));
        user.setSex("N");
        user.setStatus(Boolean.FALSE);
        save(user);
        UserLoginSuccessVO userLoginSuccessVO = new UserLoginSuccessVO();
        BeanUtil.copyProperties(user, userLoginSuccessVO);
        return R.success(userLoginSuccessVO);
    }

    @Override
    public UserLoginSuccessVO loginByUserId(Long userId) {
        User user = getById(userId);
        if (user == null || !user.getStatus()) {
            return null;
        }
        UserLoginSuccessVO userLoginSuccessVO = new UserLoginSuccessVO();
        BeanUtils.copyProperties(user, userLoginSuccessVO);
        return userLoginSuccessVO;
    }

    @Override
    public R<UserLoginSuccessVO> loginByThirdAccount(LoginDTO dto) {
        LambdaQueryWrapper<User> query = Wrappers.<User>lambdaQuery()
                .eq(User::getDeleted, Boolean.FALSE)
                .last("order by create_time desc limit 1");
        User updateUser = new User();
        switch (dto.getType()) {
            case PHONE:
                query.eq(User::getMobile, dto.getAccount());
                updateUser.setMobile(dto.getAccount());
                break;
            case EMAIL:
                query.eq(User::getEmail, dto.getAccount());
                updateUser.setEmail(dto.getAccount());
                break;
            default:
                return R.fail("不支持的登录方式");
        }
        User authUser = getOne(query);
        if (authUser != null) {
            if (!authUser.getStatus()) {
                return R.fail("当前账号未启用");
            }
            UserLoginSuccessVO userLoginSuccessVO = new UserLoginSuccessVO();
            BeanUtils.copyProperties(authUser, userLoginSuccessVO);
            return R.success(userLoginSuccessVO);
        }
        // 未注册，自动注册
        R<UserLoginSuccessVO> register = simpleRegister(dto.getAccount());
        if (register.getIsError()) {
            return R.fail(register.getMsg());
        }
        // 注册成功，绑定对应账号
        UserLoginSuccessVO data = register.getData();
        updateUser.setId(data.getId());
        updateById(updateUser);
        return R.success(data);
    }
}
